package imp

import (
	sqlc "bgs/db/sqlc"
	brandEndorseRequestGrpc "bgs/grpc/gen/service/brand_endorse_request"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
	"bytes"
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

/****************************************************************************************/
/*                               brand_endorse_request entity of helper                 */
/****************************************************************************************/

func transformBrandEndorseRequestEntityToPb(BrandEndorseRequest sqlc.BrandEndorseRequest) *brandEndorseRequestGrpc.BrandEndorseRequestEntity {
	return &brandEndorseRequestGrpc.BrandEndorseRequestEntity{
		Id:          BrandEndorseRequest.ID,
		BrandId:     BrandEndorseRequest.BrandID,
		UserId:      BrandEndorseRequest.UserID,
		Requested:   sqlc.GoTimeToPBTimestamp(BrandEndorseRequest.Requested),
		Audited:     sqlc.GoTimeToPBTimestamp(BrandEndorseRequest.Audited.Time),
		ApplyFields: string(BrandEndorseRequest.ApplyFields),
		AuditResult: BrandEndorseRequest.AuditResult,
	}
}

/****************************************************************************************/
/*                               brand_endorse_request entity of cmd                    */
/****************************************************************************************/

// ApplyBrandEndorseRequest 申请品牌代言请求
func (s *BrandAPIService) ApplyBrandEndorseRequest(ctx context.Context, req *brandEndorseRequestGrpc.ApplyBrandEndorseRequestRequest) (res *brandEndorseRequestGrpc.ApplyBrandEndorseRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_endorse_requestImp->ApplyBrandEndorseRequest:%v", req)

	res = &brandEndorseRequestGrpc.ApplyBrandEndorseRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	userID := req.UserId
	brandID := req.BrandId

	// 1 判断代言设置
	brandEndorsement, sqlErr := s.dao.Q.GetBrandEndorsementByBrandID(ctx, req.BrandId)
	if sqlErr != nil {
		if sql.ErrNoRows != sqlErr {
			err = sqlErr
		} else {
			err = fmt.Errorf("品牌未开启招募代言人 brandID:%d", req.BrandId)
		}
		return
	}
	// 查到代言设置
	if !brandEndorsement.IsOpen {
		err = fmt.Errorf("品牌关闭了招募代言人 brandID:%d", req.BrandId)
		return
	}

	if brandEndorsement.UserStratified == string(sqlc.EmUserStratificationConsumer) {
		// 检查消息记录
		// 临时
		err = fmt.Errorf("未实现对于用户的品牌最低消费金额计算 userID:%d", req.BrandId)
		return
	}

	if !brandEndorsement.NeedApplyInfo {
		err = fmt.Errorf("没有任何申请信息不可能存在%d", req.BrandId)
		return
	}

	var oApplyFields map[string]string
	if decodeErr := json.NewDecoder(strings.NewReader(req.ApplyFields)).Decode(&oApplyFields); decodeErr != nil {
		err = fmt.Errorf("无法解析申请信息: %v", decodeErr)
		return
	}
	fields := brandEndorsement.ApplyInfoFields
	for _, field := range fields {
		if oApplyFields[field] == "" {
			err = fmt.Errorf("缺少申请信息: %s", field)
			return
		}
	}

	// 2 判断是否申请用户已经是品牌的代言人
	brandSpokesmanPtr, getErr := s.spokesmanService.GetBrandSpokesmanPtr(ctx, q, userID, brandID)
	if getErr != nil {
		if sql.ErrNoRows != getErr {
			err = getErr
			return
		}
		slog.Infof("还不是品牌代言人,继续")
	} else {
		// 查到代言人了
		if brandSpokesmanPtr.Status == string(sqlc.EmRecordStatusNormal) {
			err = fmt.Errorf("已经是品牌代言人了userID:%d,brandID:%d", userID, brandID)
			return
		}
	}

	// 没找到代言人或者代言人处于作废状态,需要继续寻找是否有相同的申请记录
	pendingRequestCount, sqlErr := s.dao.Q.CountPendingBrandEndorseRequestByBrandIDAndUserID(ctx,
		sqlc.CountPendingBrandEndorseRequestByBrandIDAndUserIDParams{
			UserID:  userID,
			BrandID: brandID,
		},
	)
	if sqlErr != nil {
		err = sqlErr
		return
	}
	slog.Infof("寻找是否有相同的申请记录=>%d", pendingRequestCount)

	if pendingRequestCount > 0 {
		err = fmt.Errorf("已经存在代言人申请记录userID:%d,brandID:%d", userID, brandID)
		return
	}
	var needSendNotify bool
	var brandEndorseRequest sqlc.BrandEndorseRequest
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		// 3 创建代言申请,如果是自动审核,设置品牌代言关系
		brandEndorseRequest, err = q.CreateBrandEndorseRequest(ctx, sqlc.CreateBrandEndorseRequestParams{
			BrandID:     brandID,
			UserID:      userID,
			ApplyFields: []byte(req.ApplyFields),
			Audited:     util.IfThenElse(brandEndorsement.IsAutoApproved, sqlc.NTimeFromTime(time.Now()), sql.NullTime{}).(sql.NullTime),
			AuditResult: string(util.IfThenElse(brandEndorsement.IsAutoApproved, sqlc.EmAuditResultApproved, sqlc.EmAuditResultPending).(sqlc.EmAuditResult)),
		})
		if err != nil {
			return err
		}
		slog.Infof("创建品牌代言申请成功=>", brandEndorseRequest.ID)
		// 此处brandEndorseRequest.AuditResult只有pending和approved两种结果
		// userID := brandEndorseRequest.UserID
		// brandID := brandEndorseRequest.BrandID
		if brandEndorseRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
			// 插入/更新品牌代言关系
			endorseObjectKey := fmt.Sprintf("%d-0", brandID)
			_, err = q.UpsertSpokesman(ctx, sqlc.UpsertSpokesmanParams{
				UserID:           userID,
				BrandID:          brandID,
				EndorseObjectKey: endorseObjectKey,
				AliasName:        oApplyFields[string(sqlc.EmBrandEndorseApplyFieldNickName)],
				Became:           time.Now(),
			})
			if err != nil {
				return err
			}

			err = s.userService.UpdateUserStatSinceBecomeBrandSpokesman(ctx, q, userID)
			if err != nil {
				return err
			}
			slog.Infof("s1 更新用户统计 ok")

			err = s.brandService.UpdateBrandStatSpokesmanCountSinceUpsertBrandSpokesman(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新品牌统计的spokesman_count ok")

			needSendNotify = true
		} else {
			err = s.brandService.UpdateBrandStatEndorseRequestCountSinceCreateBrandEndorsePendingRequest(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新品牌统计的endorse_request_to_audit_count ok")
		}
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if needSendNotify {
		notifyParam, genErr := s.brandService.GenEndorseRequestAuditedNotifyMessage(ctx, s.dao.Q, brandEndorseRequest.ID)
		if genErr != nil {
			slog.Errorf("ApplyBrandEndorseRequest 品牌生成代言人审核结果消息失败:%s", genErr.Error())
			// 不影响主流程因此不赋值给err
		}
		sendErr := s.wxpMinaService.SendNotify(ctx, &notifyParam)
		if sendErr != nil {
			slog.Errorf("ApplyBrandEndorseRequest 发送mina代言人审核结果提醒失败:%s", sendErr.Error())
		}
	}
	res.BrandEndorseRequest = transformBrandEndorseRequestEntityToPb(brandEndorseRequest)
	return
}

// AuditBrandEndorseRequest 审核品牌代言请求
func (s *BrandAPIService) AuditBrandEndorseRequest(ctx context.Context, req *brandEndorseRequestGrpc.AuditBrandEndorseRequestRequest) (res *brandEndorseRequestGrpc.AuditBrandEndorseRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_endorse_requestImp->AuditBrandEndorseRequest:%v", req)
	res = &brandEndorseRequestGrpc.AuditBrandEndorseRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	if req.AuditResult == string(sqlc.EmAuditResultPending) {
		err = fmt.Errorf("无效的审核结果:%s", req.AuditResult)
		return
	}

	var needSendNotify bool
	var brandEndorseRequest sqlc.BrandEndorseRequest
	err = s.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {

		arg := sqlc.UpdateBrandEndorseRequestParams{
			ID:          req.Id,
			Audited:     sqlc.NTimeFromTime(sqlc.PBTimestampToGoTime(req.Audited)),
			AuditResult: req.AuditResult,
		}
		brandEndorseRequest, err = q.UpdateBrandEndorseRequest(ctx, arg)
		if err != nil {
			return err
		}
		var oApplyFields map[sqlc.EmBrandEndorseApplyField]string
		if decodeErr := json.NewDecoder(bytes.NewReader(brandEndorseRequest.ApplyFields)).Decode(&oApplyFields); err != nil {
			err = fmt.Errorf("无法解析申请信息: %s", decodeErr)
			return
		}

		if brandEndorseRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
			// 插入/更新品牌代言关系
			userID := brandEndorseRequest.UserID
			brandID := brandEndorseRequest.BrandID
			endorseObjectKey := fmt.Sprintf("%d-0", brandID)
			_, err = q.UpsertSpokesman(ctx, sqlc.UpsertSpokesmanParams{
				UserID:           userID,
				BrandID:          brandID,
				EndorseObjectKey: endorseObjectKey,
				AliasName:        oApplyFields[sqlc.EmBrandEndorseApplyFieldNickName],
				Became:           time.Now(),
			})
			if err != nil {
				return err
			}
			err = s.userService.UpdateUserStatSinceBecomeBrandSpokesman(ctx, q, userID)
			if err != nil {
				return err
			}
			slog.Infof("s1 更新用户统计 ok")

			err = s.brandService.UpdateBrandStatSpokesmanCountSinceUpsertBrandSpokesman(ctx, q, brandID)
			if err != nil {
				return
			}
			slog.Infof("s2 更新品牌统计的spokesman_count ok")

		} else if brandEndorseRequest.AuditResult == string(sqlc.EmAuditResultApproved) {
			// 拒绝,暂时什么都不做
			slog.Infof("审核代言人拒绝")
		}
		needSendNotify = true
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if needSendNotify {
		notifyParam, genErr := s.brandService.GenEndorseRequestAuditedNotifyMessage(ctx, s.dao.Q, brandEndorseRequest.ID)
		if genErr != nil {
			slog.Errorf("AuditBrandEndorseRequest 生成代言人审核结果消息失败:%s", genErr.Error())
			// 不影响主流程因此不赋值给err
		}
		sendErr := s.wxpMinaService.SendNotify(ctx, &notifyParam)
		if sendErr != nil {
			slog.Errorf("AuditBrandEndorseRequest 发送mina代言人审核结果提醒失败:%s", sendErr.Error())
		}
	}
	res.BrandEndorseRequest = transformBrandEndorseRequestEntityToPb(brandEndorseRequest)
	return
}

/****************************************************************************************/
/*                               brand_endorse_request entity of query                  */
/****************************************************************************************/

// GetBrandEndorseRequest 获取单个品牌代言请求
func (s *BrandAPIService) GetBrandEndorseRequest(ctx context.Context, req *brandEndorseRequestGrpc.GetBrandEndorseRequestRequest) (res *brandEndorseRequestGrpc.GetBrandEndorseRequestResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_endorse_requestImp->GetBrandEndorseRequest:%v", req)
	res = &brandEndorseRequestGrpc.GetBrandEndorseRequestResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	brandEndorseRequest, err := s.dao.Q.GetBrandEndorseRequest(ctx, req.Id)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.BrandEndorseRequest = transformBrandEndorseRequestEntityToPb(brandEndorseRequest)
	return
}

// GetBrandEndorseRequestByBrandIDAndUserID 根据品牌ID和用户ID获取最新的代言请求
func (s *BrandAPIService) GetBrandEndorseRequestByBrandIDAndUserID(ctx context.Context, req *brandEndorseRequestGrpc.GetBrandEndorseRequestByBrandIDAndUserIDRequest) (res *brandEndorseRequestGrpc.GetBrandEndorseRequestByBrandIDAndUserIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_endorse_requestImp->GetBrandEndorseRequestByBrandIDAndUserID:%v", req)
	res = &brandEndorseRequestGrpc.GetBrandEndorseRequestByBrandIDAndUserIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	q := s.dao.Q
	userID := req.UserId
	brandID := req.BrandId

	brandEndorseRequest, sqlErr := q.GetBrandEndorseRequestByBrandIDAndUserID(ctx, sqlc.GetBrandEndorseRequestByBrandIDAndUserIDParams{
		BrandID: brandID,
		UserID:  userID,
	})
	if sqlErr != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    util.Int32IfThenElse(sql.ErrNoRows == sqlErr, 404, 400),
			Msg:     sqlErr.Error(),
		}
		return
	}
	res.BrandEndorseRequest = transformBrandEndorseRequestEntityToPb(brandEndorseRequest)
	return
}

/****************************************************************************************/
/*                               brand_endorse_requestJoins entity of helper            */
/****************************************************************************************/

func transformBrandEndorseRequestWithUserInfoEntityToPb(o sqlc.ListBrandEndorseRequestWithUserInfosByBrandIDAndAuditResultsRow) *brandEndorseRequestGrpc.BrandEndorseRequestWithUserInfoEntity {
	return &brandEndorseRequestGrpc.BrandEndorseRequestWithUserInfoEntity{
		Id:          o.ID,
		BrandId:     o.BrandID,
		UserId:      o.UserID,
		Requested:   sqlc.GoTimeToPBTimestamp(o.Requested),
		Audited:     sqlc.GoTimeToPBTimestamp(o.Audited.Time),
		ApplyFields: string(o.ApplyFields),
		AuditResult: o.AuditResult,
		UserPic:     o.UserPic.String,
	}
}

func mapBrandEndorseRequestWithUserInfoEntityToPb(list []sqlc.ListBrandEndorseRequestWithUserInfosByBrandIDAndAuditResultsRow, f func(sqlc.ListBrandEndorseRequestWithUserInfosByBrandIDAndAuditResultsRow) *brandEndorseRequestGrpc.BrandEndorseRequestWithUserInfoEntity) []*brandEndorseRequestGrpc.BrandEndorseRequestWithUserInfoEntity {
	r := make([]*brandEndorseRequestGrpc.BrandEndorseRequestWithUserInfoEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               brand_endorse_requestJoins entity of query                  */
/****************************************************************************************/

// ListBrandEndorseRequestWithUserInfosByBrandID  根据品牌ID获取代言请求+用户信息
func (s *BrandAPIService) ListBrandEndorseRequestWithUserInfosByBrandID(ctx context.Context, req *brandEndorseRequestGrpc.ListBrandEndorseRequestWithUserInfosByBrandIDRequest) (res *brandEndorseRequestGrpc.ListBrandEndorseRequestWithUserInfosByBrandIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("brand_endorse_requestImp->ListBrandEndorseRequestWithUserInfosByBrandID:%v", req)

	res = &brandEndorseRequestGrpc.ListBrandEndorseRequestWithUserInfosByBrandIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	brandID := req.BrandId
	auditResults := req.AuditResults

	total, err := q.CountBrandEndorseRequestWithUserInfosByBrandIDAndAuditResults(ctx, sqlc.CountBrandEndorseRequestWithUserInfosByBrandIDAndAuditResultsParams{
		Created:      sqlc.PBTimestampToGoTime(req.Ts),
		BrandID:      brandID,
		AuditResults: auditResults,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	brandEndorseRequests, err := q.ListBrandEndorseRequestWithUserInfosByBrandIDAndAuditResults(ctx, sqlc.ListBrandEndorseRequestWithUserInfosByBrandIDAndAuditResultsParams{
		Limit:        req.Limit,
		Offset:       req.Offset,
		Created:      sqlc.PBTimestampToGoTime(req.Ts),
		BrandID:      req.BrandId,
		AuditResults: auditResults,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.BrandEndorseRequestWithUserInfos = mapBrandEndorseRequestWithUserInfoEntityToPb(brandEndorseRequests, transformBrandEndorseRequestWithUserInfoEntityToPb)
	return
}
